
   
<script>
import mapboxgl from 'mapbox-gl';
import { onMounted } from 'vue'
import { reactive, toRefs } from 'vue'
import proj4 from 'proj4';
import { getPointByExtent, getPointByWkt } from "@/util/request"
import * as turf from '@turf/turf';
import * as Util from "@/util/GeomUtil"
import { ElMessage } from "element-plus"
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';






export default {
    setup() {

        const data = reactive({
            zoom: 13,
            latitude: 0,
            longitude: 0,
            coorx: 0,
            coory: 0,
            tmsx: 0,
            tmsy: 0,
            isEdit: false,
            is3D: false,

            min_X: 0,
            max_X: 0,
            min_Y: 0,
            max_Y: 0,

            tableData: [],

            tableHeight: '0%',
            currentPage: 1,
            tableTotal: 0
        })

        // 定义投影转换参数
        proj4.defs('EPSG:4326', '+proj=longlat +datum=WGS84 +no_defs');
        proj4.defs('EPSG:3857', '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs');

        const polygonGeojson = {
            "type": "FeatureCollection",
            "features": []
        }

        var pointGeojson = {
            'type': 'FeatureCollection',
            'features': [],
            //extent移动事件
            'viewbox': {
                min_X: 0,
                max_X: 0,
                min_Y: 0,
                max_Y: 0,
            }
        };


        var bulid = {
            'id': 'bulid-layer',
            'type': 'fill-extrusion',
            'source': {
                'type': 'geojson',
                'data': polygonGeojson
            },
            'paint': {
                'fill-extrusion-color': '#0000FF', // 面颜色
                'fill-extrusion-height': [
                    'interpolate',
                    ['linear'],
                    ['zoom'],
                    15,
                    0,
                    15.05,
                    ['get', 'height']
                ]
            }
        }

        var editPoint = {
            'id': 'point',
            'type': 'circle',
            'source': {
                // 'id':'point-source',
                'type': 'geojson',
                'data': pointGeojson
            },
            'paint': {
                'circle-radius': 4,
                'circle-color': '#00FF00', // red color
                'circle-stroke-color': '#0000FF', // green color
                'circle-stroke-width': 2 // stroke width
            }
        };

        var pointJsonLayer = {
            'id': 'ps-point-json',
            'type': 'circle',
            'source': {
                'type': 'geojson',
                'data': pointGeojson
            },
            'paint': {
                'circle-color': '#0000FF',
                'circle-radius': 3,
            }
        };



        //线图层
        var vectorLine = {
            id: 'vector-tile-layer',
            type: 'line',
            source: {
                'bounds': [113.1287154680459, 22.903336495087977, 113.27962345262513, 23.01022520493561],
                'type': 'vector',
                // 'tiles': [`http://${window.location.hostname}:9999/geoserver/gwc/service/tms/1.0.0/zhouweijun%3Aps_line_n_onlyshape@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf`],
                'tiles': [`http://localhost:8055/mvt_server/layer1/{z}/{x}/{y}`],
                'scheme': "tms"
            },
            'source-layer': 'default',
            paint: {
                'line-color': 'green',
                'line-width': 3,
            },
            layout: {
                'line-cap': 'round',
                'line-join': 'round'
            }
        }
        var line_symbol = {
            id: 'line_symbol',
            type: 'symbol',
            source: {
                'bounds': [113.1287154680459, 22.903336495087977, 113.27962345262513, 23.01022520493561],
                'type': 'vector',
                'tiles': [`http://localhost:8055/mvt_server/layer1/{z}/{x}/{y}`],
                'scheme': "tms"
            },
            'source-layer': 'default',
            'layout': {
                'text-font': ['Open Sans Semibold',
                    'Arial Unicode MS Bold'],
                'text-field': ['get', 'pipemat1'],
                'symbol-placement': 'line',
                'text-size': 14
            },
            minzoom: 18, // 最小缩放级别为17
            maxzoom: 22  // 最大缩放级别为22
        }

        //点图层
        var vectorPoint = {
            id: 'ps-point',
            type: 'circle',
            source: {
                'bounds': [113.1287154680459, 22.903336495087977, 113.27962345262513, 23.01022520493561],
                'type': 'vector',
                'tiles': [`http://${window.location.hostname}:9999/geoserver/gwc/service/tms/1.0.0/zhouweijun%3Aps_point_n_onlyshape@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf`],
                'scheme': "tms"
            },
            'source-layer': 'ps_point_n_onlyshape',
            paint: {
                'circle-color': '#0000FF',
                'circle-radius': 3,
            },
            minzoom: 16, // 最小缩放级别为17
            maxzoom: 22  // 最大缩放级别为22
        }

        // #endregion

        //定义一个webSocket连接
        var socket = null;
        //发送变更的数据
        var updatePoints = {}

        var map = null;
        onMounted(() => {
            mapboxgl.accessToken = 'pk.eyJ1Ijoibm9ydGh2aSIsImEiOiJjbGVydjV6YWkwMGFhNDFudG14ZXU3MXM3In0.o6cCmMVC4u7jsSQeN9BNiQ';


            map = new mapboxgl.Map({
                container: 'map',
                style: 'mapbox://styles/mapbox/streets-v12',
                center: [113.2025401687622, 22.986097263451536],
                zoom: data.zoom,
                maxZoom: 21.99,
                scheme: 'https'

            });

            // 增加控件
            var nav = new mapboxgl.NavigationControl();
            map.addControl(nav, 'bottom-right');


            map.on('moveend', function () {
                //当视图发送改变并且zoom大于19就请求控制点
                const extent = map.getBounds();
                data.min_X = extent._sw.lng
                data.max_X = extent._ne.lng
                data.min_Y = extent._sw.lat
                data.max_Y = extent._ne.lat



                //连接webSocket
                if (data.zoom >= 17) {
                    if (socket == null || socket.readyState == WebSocket.CLOSED) {
                        socket = new WebSocket(`ws://${window.location.hostname}:8044/my-websocket-vec`)
                        socket.onopen = function () {
                            console.log("已连接服务器进行实时更新")
                        };
                        socket.onmessage = function (event) {
                            const parseObj = JSON.parse(event.data)
                            console.log(parseObj)
                            for (let i = 0; i < parseObj.length; i++) {
                                const item = parseObj[i];
                                for (let j = 0; j < pointGeojson.features.length; j++) {
                                    let feature = pointGeojson.features[j]
                                    if (feature.properties.id == item[0]) {
                                        feature.geometry.coordinates = [parseFloat(item[1]), parseFloat(item[2])]
                                    }
                                }
                            }
                            map.getSource('ps-point-json').setData(pointGeojson);
                            map.getSource('point').setData(pointGeojson);

                        };
                    }

                    const mercatorCoord1 = proj4('EPSG:4326', 'EPSG:3857', [data.min_X, data.min_Y]);
                    const mercatorCoord2 = proj4('EPSG:4326', 'EPSG:3857', [data.max_X, data.max_Y]);
                    const par = {
                        'minx': mercatorCoord1[0],
                        'miny': mercatorCoord1[1],
                        'maxx': mercatorCoord2[0],
                        'maxy': mercatorCoord2[1],
                    }
                    getPointByExtent(par).then(res => {
                        pointGeojson.features = []
                        res.forEach(element => {
                            var coor = Util.getXYBywktPoint(element.geom)
                            coor = proj4('EPSG:3857', 'EPSG:4326', coor);
                            pointGeojson.features.push({
                                'type': 'Feature',
                                'geometry': {
                                    'type': 'Point',
                                    'coordinates': coor
                                },
                                "properties": {
                                    "id": element.surveyNo
                                }
                            })
                        });
                        map.getSource('ps-point-json').setData(pointGeojson);
                        map.getSource('point').setData(pointGeojson);

                    })

                } else {
                    pointGeojson.features = []
                    map.getSource('ps-point-json').setData(pointGeojson);

                    if (socket != null && socket.readyState == WebSocket.OPEN) {
                        socket.close()
                        console.log("已关闭实时更新")

                    }
                }

                // //如果未开启编辑模式，就不请求控制点
                // if (data.isEdit) {
                //     if (data.zoom >= 19) {

                //         var mercatorCoord1 = proj4('EPSG:4326', 'EPSG:3857', [data.min_X, data.min_Y]);
                //         var mercatorCoord2 = proj4('EPSG:4326', 'EPSG:3857', [data.max_X, data.max_Y]);
                //         const par = {
                //             'minx': mercatorCoord1[0],
                //             'miny': mercatorCoord1[1],
                //             'maxx': mercatorCoord2[0],
                //             'maxy': mercatorCoord2[1],
                //         }
                //         getPointByExtent(par).then(res => {
                //             geojson.features = []
                //             res.forEach(element => {
                //                 var coor = Util.getXYBywktPoint(element.geom)
                //                 coor = proj4('EPSG:3857', 'EPSG:4326', coor);
                //                 geojson.features.push({
                //                     'type': 'Feature',
                //                     'geometry': {
                //                         'type': 'Point',
                //                         'coordinates': coor
                //                     }, "properties": {
                //                         "id": element.surveyNo
                //                     }
                //                 })
                //             });
                //             map.getSource('point').setData(pointGeojson);
                //         })
                //     }
                // }


            });

            // #region 编辑点按下事件
            map.on('mousedown', 'point', (e) => {
                var target = {
                    "type": "Feature",
                    "geometry": {
                        "type": "Point",
                        "coordinates": [e.lngLat.lng, e.lngLat.lat]
                    }
                };

                // 使用nearestPoint函数查询最近的点
                var nearest = turf.nearestPoint(target, pointGeojson);
                // 阻止地图的默认拖动行为
                e.preventDefault();
                var onMoveFun = () => { };
                map.on('mousemove', onMoveFun = (e) => {
                    onMove(e, nearest.properties.featureIndex)
                });
                map.once('mouseup', (ex) => {
                    var mercatorCoord1 = proj4('EPSG:4326', 'EPSG:3857', [ex.lngLat.lng, ex.lngLat.lat]);
                    updatePoints[nearest.properties.id] = [...mercatorCoord1, ex.lngLat.lng, ex.lngLat.lat, e.lngLat.lng, e.lngLat.lat]
                    map.off('mousemove', onMoveFun);
                });
            });

            //设置编辑点的鼠标样式
            const canvas = map.getCanvasContainer();
            map.on('mouseenter', 'point', () => {
                canvas.style.cursor = 'move';
            });

            map.on('mouseleave', 'point', () => {
                canvas.style.cursor = '';
            });

            function onMove(e, index) {
                const coords = e.lngLat;
                pointGeojson.features[index].geometry.coordinates = [coords.lng, coords.lat];
                map.getSource('point').setData(pointGeojson);
            }
            //#endregion


            // map.on('click', 'ps-point', (e) => {
            //     var par = {
            //         'coorx': data.coorx,
            //         'coory': data.coory,
            //         'distance': 10
            //     }
            //     console.log(par)
            //     var feature = e.features[0];
            //     var propertyValue = feature.properties['survey_no'];
            //     alert(propertyValue);
            // });
            map.on('zoom', function () {
                data.zoom = map.getZoom().toFixed(2)
            });
            map.on('mousemove', function (e) {
                data.longitude = e.lngLat.lng.toFixed(7)
                data.latitude = e.lngLat.lat.toFixed(7)

                var mercatorCoord = proj4('EPSG:4326', 'EPSG:3857', [e.lngLat.lng, e.lngLat.lat]);
                data.coorx = mercatorCoord[0].toFixed(2)
                data.coory = mercatorCoord[1].toFixed(2)

                //经纬度转tms行列号
                var tmsxy = Util.lnglat2tms(e.lngLat.lng, e.lngLat.lat, data.zoom)
                data.tmsx = tmsxy[0]
                data.tmsy = tmsxy[1]
            });

            //地图挂载完成添加地图服务
            map.on('load', function () {
                console.log(vectorLine, vectorPoint, editPoint, bulid)
                map.addLayer(vectorLine);
                map.addLayer(pointJsonLayer)
                map.addLayer(line_symbol)

                // map.addLayer(vectorPoint);
                map.addLayer(editPoint);
                map.setLayoutProperty('point', 'visibility', 'none');

                map.addLayer(bulid);
            });
        })

        const startEdit = () => {
            const centerPoint = [(data.min_X + data.max_X) / 2, (data.max_Y + data.min_Y) / 2]
            if (data.isEdit) {
                map.setLayoutProperty('point', 'visibility', 'visible');
                map.setLayoutProperty('ps-point-json', 'visibility', 'none');
                map.flyTo({
                    center: centerPoint,
                    zoom: 19,
                    speed: 2
                });
                map.once('moveend', function () {
                    map.setMinZoom(19);
                });

            } else {
                map.setLayoutProperty('ps-point-json', 'visibility', 'visible');
                map.setLayoutProperty('point', 'visibility', 'none');
                map.setMinZoom(0);
            }
        }

        const saveEdit = () => {
            if (Object.keys(updatePoints).length === 0) {
                ElMessage({
                    message: '没有发生变更的数据',
                    type: 'success',
                })
                return
            }
            socket.send(JSON.stringify(updatePoints))
            // console.log("发送数据：")
            // console.log(JSON.stringify(updatePoints))
            ElMessage({
                message: '数据已提交',
                type: 'success',
            })
            updatePoints = {}
        }
        const updateImage = () => {
            //当视图发送改变并且zoom大于19就请求控制点
            if (data.zoom >= 19) {

                var mercatorCoord1 = proj4('EPSG:4326', 'EPSG:3857', [data.min_X, data.min_Y]);
                var mercatorCoord2 = proj4('EPSG:4326', 'EPSG:3857', [data.max_X, data.max_Y]);
                const par = {
                    'minx': mercatorCoord1[0],
                    'miny': mercatorCoord1[1],
                    'maxx': mercatorCoord2[0],
                    'maxy': mercatorCoord2[1],
                }
                getPointByExtent(par).then(res => {
                    polygonGeojson.features = []
                    res.forEach(element => {
                        var coor = Util.getXYBywktPoint(element.geom)
                        coor = proj4('EPSG:3857', 'EPSG:4326', coor);
                        polygonGeojson.features.push({
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Polygon',
                                'coordinates': [Util.getPointsOnCircle(coor[0], coor[1], 0.000008)]
                            },
                            "properties": {
                                "id": element.surveyNo,
                                "height": Util.getZBywktPoint(element.geom)
                            }
                        })
                    });
                    map.getSource('bulid-layer').setData(polygonGeojson);
                })
            }

        }

        var centerPoint = []
        const change3D = () => {
            if (data.is3D) {
                data.isEdit = false
                centerPoint = [(data.min_X + data.max_X) / 2, (data.max_Y + data.min_Y) / 2]

                map.flyTo({
                    center: centerPoint, // 目标中心点坐标
                    zoom: 19, // 目标缩放级别
                    pitch: 70, // 目标俯仰角
                    speed: 3, // 过渡速度
                    curve: 1, // 过渡曲线，0表示线性过渡，1表示平滑过渡
                });
            } else {
                map.flyTo({
                    center: centerPoint, // 目标中心点坐标
                    zoom: 19, // 目标缩放级别
                    pitch: 0, // 目标俯仰角
                    speed: 3, // 过渡速度
                    curve: 1, // 过渡曲线，0表示线性过渡，1表示平滑过渡
                });
            }

        }

        var wkt = '';
        const openTable = () => {

            const draw = new MapboxDraw({
                displayControlsDefault: false,
                controls: {
                    polygon: true,
                    trash: true
                },
                defaultMode: 'draw_polygon'
            });
            map.addControl(draw);
            map.on('draw.create', updateArea);
            map.on('draw.delete', updateArea);
            map.on('draw.update', updateArea);

            function updateArea() {
                test()
                const points = draw.getAll();
                if (points.features.length > 0) {
                    let polygon = points.features[0].geometry;


                    const center = turf.center(polygon);
                    const lnglat = center.geometry.coordinates;
                    const bbox = turf.bbox(polygon);
                    map.flyTo({
                        center: lnglat,
                        essential: true,
                        padding: { top: 50, bottom: 50, left: 50, right: 50 },
                        bbox: [bbox[0], bbox[1], bbox[2], bbox[3]]
                    });

                    for (var i = 0; i < polygon.coordinates[0].length; i++) {
                        polygon.coordinates[0][i] = proj4('EPSG:4326', 'EPSG:3857', polygon.coordinates[0][i]);
                    }

                    wkt = Util.geojsonToWKT(polygon)

                    getPointByWkt({ 'wkt': wkt, 'page': 0 }).then(res => {
                        data.tableData = [];
                        data.tableTotal = res.count;
                        for (var value of res.data) {
                            value.X = Util.getXYBywktPoint(value.geom)[0].toFixed(2)
                            value.Y = Util.getXYBywktPoint(value.geom)[1].toFixed(2)
                            data.tableData.push(value)
                        }

                    })

                }
            }
        }

        const test = () => {
            data.tableHeight = '100%'
            var timerId = setTimeout(doSomething, 310);
            function doSomething() {
                map.resize();
                clearTimeout(timerId);

            }

        }

        var markers = [];
        const handleRowDoubleClick = (row) => {
            var coor = proj4('EPSG:3857', 'EPSG:4326', [parseFloat(row.X), parseFloat(row.Y)]);
            map.flyTo({
                center: coor, // 目标中心点坐标
                zoom: 19, // 目标缩放级别

            });

            for (var i = 0; i < markers.length; i++) {
                markers[i].remove();
            }
            const marker = new mapboxgl.Marker()
                .setLngLat(coor)
                .addTo(map);
            markers.push(marker)

        }

        const pageChange = (page) => {
            console.log(wkt)
            getPointByWkt({ 'wkt': wkt, 'page': (page - 1) * 100 }).then(res => {
                data.tableData = [];
                data.tableTotal = res.count;
                for (var value of res.data) {
                    value.X = Util.getXYBywktPoint(value.geom)[0].toFixed(2)
                    value.Y = Util.getXYBywktPoint(value.geom)[1].toFixed(2)
                    data.tableData.push(value)
                }

            })
        }
        return { ...toRefs(data), saveEdit, startEdit, updateImage, change3D, openTable, handleRowDoubleClick, test, pageChange }
    }
};

</script>
   

<template>
    <div>
        <div class="container">

            <div id="map"></div>

            <div id="attribute" v-bind:style="{ height: tableHeight }">
                <div class="table">
                    <el-table :data="tableData" height="100%" highlight-current-row @row-dblclick="handleRowDoubleClick">
                        <el-table-column prop="zoneCode" label="zoneCode" />
                        <el-table-column prop="evcodeMai" label="evcodeMai" />
                        <el-table-column prop="surveyNo" label="surveyNo" width="180" />
                        <el-table-column prop="coorRecor" label="coorRecor" />
                        <el-table-column prop="pointdepth" label="pointdepth" />
                        <el-table-column prop="X" label="X" />
                        <el-table-column prop="Y" label="Y" />
                    </el-table>
                </div>
                <div class="pagination">
                    <el-pagination v-model:current-page="currentPage" small background
                        :page-count="Math.ceil(tableTotal / 100)" layout="total, prev, pager, next, jumper"
                        :total=tableTotal @current-change="pageChange" />
                </div>
            </div>
        </div>


    </div>
    <el-card class="infoCard" shadow="always">
        <table>
            <tr>
                <td>缩放级别:</td>
                <td>{{ zoom }}</td>
            </tr>
            <tr>
                <td>经度:</td>
                <td>{{ longitude }}</td>
            </tr>
            <tr>
                <td>纬度:</td>
                <td>{{ latitude }}</td>
            </tr>
            <tr>
                <td>X坐标:</td>
                <td>{{ coorx }}</td>
            </tr>
            <tr>
                <td>Y坐标:</td>
                <td>{{ coory }}</td>
            </tr>
            <tr>
                <td>TMS-X:</td>
                <td>{{ tmsx }}</td>
            </tr>
            <tr>
                <td>TMS-Y:</td>
                <td>{{ tmsy }}</td>
            </tr>
        </table>
        <el-button @click="saveEdit" type="success" plain>保存</el-button>
        <el-button @click="updateImage" type="success" plain>刷新</el-button>
        <el-button @click="openTable" type="success" plain>属性表</el-button>
        <!-- <el-button @click="test" type="success" plain>测试按钮</el-button> -->
        <el-switch v-model="isEdit" class="ml-2" inline-prompt @change="startEdit"
            style="--el-switch-on-color: #13ce66; --el-switch-off-color: #999980" active-text="关闭" inactive-text="编辑" />



        <el-switch v-model="is3D" @click="change3D" size="large" active-text="3D" inactive-text="2D" />

    </el-card>
</template>



<style scoped>
.container {
    display: flex;
    flex-direction: column;
    height: 100vh;
}


#map {
    flex-grow: 1;
    height: 100%;

}

#attribute {
    flex-grow: 0;
    overflow-y: auto;
    transition: all 0.3s ease-out;
}

.table {
    height: 90%;
}

.pagination {
    height: 10%;
    display: flex;
    justify-content: center;
    align-items: center;
}

.infoCard {
    position: absolute;
    top: 30px;
    right: 30px;
    width: 240px;
    height: 280px;
}

h1 {
    position: absolute;
    width: 100px;
    height: 100px;
    top: 100px;
    color: black;
}

table {
    font-size: 14px;
    position: absolute;
    top: 20px;
    background-color: rgb(255, 255, 255);
    border: 3px solid rgb(190, 190, 190);
    border-radius: 7px;
    width: 200px;
}

table td:nth-child(2) {
    width: 100px;
}

.infoCard .el-button {
    position: relative;
    width: 50px;
    height: 30px;
    top: 180px;
    color: black;
}

.el-switch {
    position: relative;
    top: 180px;
    margin-right: 20px;
}

#map {
    width: 100%;
}
</style>